﻿namespace Busconeitor.BusinessLayer.Kernel
{
    using Domain.Entities;
    using Domain.Utils.SimpleList;
    using DataLayer;
    using System;
    using Domain.Utils.SortMethods;

    public class SearchResults
    {
        #region Atributos

        private const string FormatExecutionTime = "%.4f";
        private int _mMaxPages;
        private int mSelectedPage;
        private long mInitTime;
        private long _mEndTime;
        private string _mQuery;
        private int _mTotalResults;
        //Mantengo un array con los documentos relevantes
        private DocumentoEntity[] _documentsRelevant;
        private string _originalQuery;
        private SimpleList _listQuery;
        private int _countRelevantDocument;

        #endregion

        #region Constructores

        public SearchResults(SimpleList cleanQuery, string originalQuery)
        {
            _mQuery = originalQuery;
            mInitTime = Environment.TickCount;

            if (!cleanQuery.IsEmpty())
            {
                _documentsRelevant = EngineDb.ExcecuteQuery(cleanQuery);
                _originalQuery = originalQuery;
                _listQuery = cleanQuery;

                _countRelevantDocument = (_documentsRelevant == null) ? 0 : _documentsRelevant.Length;
            }
            else
            {
                _countRelevantDocument = 0;
            }

            _mEndTime = Environment.TickCount;
        }

        #endregion

        #region Propiedades

        /// <summary>
        /// Consulta realizada.
        /// </summary>
        public string Query
        {
            get { return _mQuery; }
            set { _mQuery = value; }
        }

        /// <summary>
        /// Maxima cantidad de paginas mostradas.
        /// </summary>
        public int MaxPages
        {
            get { return _mMaxPages; }
            set { _mMaxPages = value; }
        }

        /// <summary>
        /// Cantidad de resultados a mostrar en una consulta.
        /// </summary>
        public int TotalResults
        {
            get { return _mTotalResults; }
            set { _mTotalResults = value; }
        }

        public DocumentoEntity[] Documents
        {
            get { return _documentsRelevant; }
            set { _documentsRelevant = value; }
        }

        public SimpleList ListQuery
        {
            get { return _listQuery; }
            set { _listQuery = value; }
        }

        #endregion
       
        #region Metodos

        public string GetSearchTime()
        {
            return ((double) (_mEndTime - mInitTime)/1000) + " seg.";
        }

        /// <summary>
        /// Resuelve el modelo vectorial y deja solo los resultados relevantes para la busqueda.
        /// </summary>
        public void ComputeVectorialModel()
        {
            if (_countRelevantDocument == 0)
            {
                return;
            }

            // Obtengo la cantidad total de documentos que hay en la bd
            var totalDocuments = DocumentDb.GetCountDocument();

            // Calculo el TF-IDF por cada documento
            for (var i = 0; i < _documentsRelevant.Length; i++)
            {
                _documentsRelevant[i].GetWTrDi(totalDocuments);
            }

            // Ordena por la relevancia de forma decreciente
            Ordenamiento.QuickSort(_documentsRelevant);

            // Solo tomo aquellos que cumplen con con la condicion de minimo aceptable
            for (var i = _documentsRelevant.Length - 1; i >= 0; i--)
            {
                if (_documentsRelevant[i].GetWTrDi(totalDocuments) >= SearchEngine.MinAceptableValue)
                {
                    _countRelevantDocument = i + 1;
                    break;
                }
            }

            var realDocuments = new DocumentoEntity[_countRelevantDocument];
            Array.Copy(_documentsRelevant, 0, realDocuments, 0, _countRelevantDocument);

            _documentsRelevant = realDocuments;
            _mMaxPages = 1;
            _mTotalResults = _documentsRelevant.Length;
        }

        public void Complete()
        {
            if (_countRelevantDocument == 0) // la busqueda es fallida, no hay documentos con la palabra buscada
            {
                _mEndTime = Environment.TickCount;
                return;
            }

            // es para armar fragmento desde el indice mas cercano.
            DocumentDb.GetDocumentsMinIndex(_documentsRelevant, 1, _listQuery);

            for (var i = 0; i < _documentsRelevant.Length; i++)
            {
                DocumentDb.BuildFragment(_documentsRelevant[i], true);
            }
        }

        #endregion
    }
}
